package org.istt.web;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.istt.domain.Group;
import org.istt.domain.Menu;
import org.istt.domain.MenuTree;
import org.istt.service.GroupManager;
import org.istt.service.MenuManager;
import org.istt.service.MenuTreeManager;
import org.springframework.beans.factory.annotation.Autowired;

import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.ActionSupport;

public class MenuAction extends ActionSupport {
    /**
	 * 
	 */
	private static final long serialVersionUID = 1L;
	private String actAddMainMenu;
    private String actEditMainMenu;
    private String cancel;
    private String delete;
    private String fatherMenuId;
    @Autowired
	private GroupManager groupManager;
    private String id;
    private final Log log = LogFactory.getLog(MenuAction.class);
    private List<Menu> lstAllMenu;
    private List<Menu> lstMainMenu;
    private List lstMenu;
    
    private List<Menu> lstSubMenu;
    
    private List<Menu> mainMenus;

	private Menu menu;
	
	private MenuManager menuManager;
	
	private MenuTreeManager menuTreeManager;
	
	private String outputMenu;

	@SuppressWarnings({ "rawtypes", "unchecked" })
	public String delete(){
    	Menu mnu = this.menuManager.getMenuById(this.menu.getId().toString());
    	// Is main-menu
    	if(mnu.getIsFather()){
    		//Remove all sub-menu
    		if(mnu.getMenuTrees().size()!=0){
    			
        		// Remove all sub-menu
        		for (int i = 0; i < mnu.getMenuTrees().size(); i++) {
        			
        			Iterator<MenuTree> it = mnu.getMenuTrees().iterator();
        			while(it.hasNext()){
        				MenuTree objMenuTree = it.next();
        				//Update is_father field to TRUE
        				Menu submenu = this.menuManager.getMenuById(objMenuTree.getChildMenuId().toString());

        				submenu.setIsFather(true);
        				this.menuManager.saveMenu(submenu);
        				
        				// Remove references on TBL_MENUTREE
        				this.menuTreeManager.removeMenuTree(objMenuTree.getId().toString());
        				
        			}
				}
        	}

    		//TODO: Update position for other menu
    		List<Menu> lstMainMenu = getLstAllMenu();
    		int positionCounter = 0;
    		for (Menu menu : lstMainMenu) {
				if(menu.getPosition()>mnu.getPosition()){
					menu.setPosition(mnu.getPosition()+positionCounter);
					
					this.menuManager.saveMenu(menu);
					
					positionCounter++;
				}
			}
    	}else{
    		
        	
        	//TODO: Update position for other sub-menu
        	Menu newFather = this.menuTreeManager.getFatherMenu(mnu.getId().toString());
        	Set<MenuTree> setMnu = newFather.getMenuTrees();
        	int positionCounter = 0;
        	for (Iterator<MenuTree> iterator = setMnu.iterator(); iterator.hasNext();) {
				MenuTree menuTree = iterator.next();
				Menu subMenu = this.menuManager.getMenuById(menuTree.getChildMenuId().toString());
				if(subMenu.getPosition()>mnu.getPosition()){
					subMenu.setPosition(mnu.getPosition()+positionCounter);
					
					this.menuManager.saveMenu(subMenu);

					positionCounter++;
				}
			}
        	
        	// Remove submenu
        	this.menuTreeManager.removeMenuTree(mnu.getId().toString());
        	
    	}
    	// Remove menu
    	this.menuManager.removeMenu(mnu.getId().toString());
    	
    	List<String> args = new ArrayList<String>();
    	args.add(mnu.getName());
        ActionContext.getContext().getSession().put("message", getText("menu.msg.delete", args));
        
        return "delete";
    }

	public String down(){
    	log.debug("----> Down");
    	if(this.id!=null && !"".equals(this.id)){
    		log.debug("----> Menuid: "+this.id);
    		Menu mnu = (Menu)this.menuManager.getMenuById(this.id);
    			if(mnu.getIsFather()){
    				List<Menu> fatherMnus = this.menuManager.getFatherMenu();
    				if(fatherMnus!=null && fatherMnus.size()!=0 && mnu.getPosition()<fatherMnus.size()){
    					for (Menu menu : fatherMnus) {
    						if(menu.getPosition()== mnu.getPosition()+1){
    							log.debug("Update position for menu...");
    							menu.setPosition(mnu.getPosition());
    	        				menuManager.saveMenu(menu);
    	        				
    	        				mnu.setPosition(mnu.getPosition()+1);
    	        				menuManager.saveMenu(mnu);
    	        				
    	        				break;
    						}
						}
    				}
    			}else{
    				//TODO: Gets menu that has position previous current menu
    				Menu father = this.menuTreeManager.getFatherMenu(this.id);
    				Set<MenuTree> menutrees = father.getMenuTrees();
    				if(mnu.getPosition() < menutrees.size()){
    					for (Iterator<MenuTree> iterator = menutrees.iterator(); iterator.hasNext();) {
    						
    						MenuTree mnutree = iterator.next();
    						Menu previousMnu = this.menuManager.getMenuById(mnutree.getChildMenuId().toString());
    						
    						log.debug("Start searching menu..."+previousMnu.getName()+" | Position: "+previousMnu.getPosition());
    						if(previousMnu.getPosition()== mnu.getPosition()+1){
    							log.debug("Update position for menu...");
    							previousMnu.setPosition(mnu.getPosition());
    							menuManager.saveMenu(previousMnu);
    							
    							mnu.setPosition(mnu.getPosition()+1);
    							menuManager.saveMenu(mnu);
    							
    							break;
    						}	
    					}
    				}
    			}
    	}
    	return SUCCESS;
    }

	public String edit(){
    	
    	 if(this.id!=null){
    		if(this.menuManager!=null){
    			 this.menu = (Menu)this.menuManager.getMenuById(this.id);
    			 Menu fatherMnu = this.menuTreeManager.getFatherMenu(this.id);
    			 if(fatherMnu!=null){
    				 this.fatherMenuId = fatherMnu.getId().toString();
    			 }
    		 }
         }
    	 else{
    		 this.menu = new Menu();
         }
    	 
    	return SUCCESS;
    }

	public String execute() {
    	
        if (cancel != null) {
            return "cancel";
        }
        if (delete != null) {
            return delete();
        }
        
        return SUCCESS;
    }

	public String getActAddMainMenu() {
		return actAddMainMenu;
	}

	public String getActEditMainMenu() {
		return actEditMainMenu;
	}

	public String getCancel() {
		return cancel;
	}
    public String getDelete() {
		return delete;
	}
	public String getFatherMenuId() {
		return fatherMenuId;
	}
	
	 public GroupManager getGroupManager() {
		return groupManager;
	}
    
    public String getId() {
		return id;
	}
    
    public List<Menu> getLstAllMenu() {
		this.lstAllMenu = menuManager.getMenuTrees();
		return lstAllMenu;
	}
    
    public List<Menu> getLstMainMenu() {
		log.debug("-----------getLstMainMenu");
		List<Menu> lstMnu = menuManager.getMenuTrees();
		this.lstMainMenu = new ArrayList<Menu>();
		for (int i = 0; i < lstMnu.size(); i++) {
			Menu mnu = lstMnu.get(i);
			if(mnu.getIsFather()){
				this.lstMainMenu.add(mnu);
			}
		}
		return lstMainMenu;
	}
    
    
    public List getLstMenu() {
		return lstMenu;
	}
    public List<Menu> getLstSubMenu() {
		return lstSubMenu;
	}
    
	public List<Menu> getMainMenus() {
		List<Menu> lstMnu = menuManager.getMenuTrees();
		this.mainMenus = new ArrayList<Menu>();
		for (int i = 0; i < lstMnu.size(); i++) {
			Menu mnu = lstMnu.get(i);
			if(this.id!=null && this.id.equals(mnu.getId().toString())){
				continue;
			}
			if(mnu.getIsFather()){
				this.mainMenus.add(mnu);
			}
		}
		return mainMenus;
	}

	public Menu getMenu() {
		return menu;
	}
	
	

	public MenuManager getMenuManager() {
		return menuManager;
	}

	public MenuTreeManager getMenuTreeManager() {
		return menuTreeManager;
	}

	public String getOutputMenu() {
		return outputMenu;
	}

	public String list(){
		return SUCCESS;
	}

	/***
	 * Load menu-tree on GUI
	 * @return
	 */
	public String load(){
		try {
			if(ActionContext.getContext().getSession().get(WebConstants.MENU_SESSION)!=null){
				this.outputMenu = (String)ActionContext.getContext().getSession().get(WebConstants.MENU_SESSION);
			}
		} catch (Exception e) {
			
			e.printStackTrace();
		}
		
		return SUCCESS;
	}

	public String loadmenu(){
		this.lstMenu = menuManager.getListMenuBeans();
		
		return SUCCESS;
	}

	public String save() {
	        if (log.isDebugEnabled()) log.debug("entering 'save' method");
	        // Case Update
	        if(menu.getId()!=null && menu.getId()!=0){
	        	if (log.isDebugEnabled()) log.debug("Update menu information...");
	        	//Update
	        	if(menu.getIsFather()){
	        		
	        		// Only update when have changing
	        		if(!this.fatherMenuId.equals(menu.getId().toString())){
	        			// Remove all sub-menu and update to new position
	        			if(this.menu.getMenuTrees().size()!=0){
	        				for (int i = 0; i < this.menu.getMenuTrees().size(); i++) {
	        					Iterator<MenuTree> it = this.menu.getMenuTrees().iterator();
	        					while(it.hasNext()){
	        						MenuTree objMenuTree = it.next();
	        						try {
	        							if (log.isDebugEnabled()) log.debug("Remove menu tree...");
	        							this.menuTreeManager.removeMenuTree(objMenuTree.getId().toString());
									} catch (Exception e) {
										// TODO: handle exception
										e.printStackTrace();
									}
	        					}
	        				}
	        			}
	        			this.menuTreeManager.removeMenuTree(menu.getId().toString());
	        			
	        			//TODO: Update new position
		        		menu.setPosition(getLstMainMenu().size()+1);
	        		}
	        	}else{
	        		Menu fatherMnu = this.menuTreeManager.getFatherMenu(menu.getId().toString());
	        		// Only update when have changing
	        		if(fatherMnu==null || !this.fatherMenuId.equals(fatherMnu.getId().toString())){
	        			// Remove all sub-menu and update to new position
	        			log.debug("Menu tree of menu: "+menu.getMenuTrees().size());
	        			try {
	        				this.menuTreeManager.removeMenuTree(menu.getId().toString());
						} catch (Exception e) {
							// TODO: handle exception
							e.printStackTrace();
						}
	        			
	        			Menu newFather = this.menuManager.getMenuById(fatherMenuId);
						MenuTree menuTree = new MenuTree();
						menuTree.setChildMenuId(menu.getId());
						menuTree.setMenu(newFather);

						this.menuTreeManager.saveMenuTree(menuTree);
						
						
						log.debug("NEW POSITION "+newFather.getMenuTrees().size()+1);
						//TODO: Update new position
		        		menu.setPosition(newFather.getMenuTrees().size()+1);
	        		}
	        	}
	        	
	        	//Save menu to TBL_MENU
	        	menuManager.saveMenu(menu);
	        	
	        	//TODO: add menu to Administrator group
	        	log.debug(">>>>>>Create new menu with id: "+menu.getId());
	        	Group adminGroup = this.groupManager.getGroup(WebConstants.ROLE_ADMINISTRATOR, true);
	        	if(adminGroup!=null){
	        		Set<Menu> lstMenu = adminGroup.getMenus();
	        		//Assign new menu to Administrator group
	        		lstMenu.add(menu);
	        		adminGroup.setMenus(lstMenu);
	        		try {
	        			this.groupManager.save(adminGroup);
	        		} catch (Exception e) {
	        			// TODO: handle exception
	        			e.printStackTrace();
	        		}
	        	}
	        	
	        }else{ // Case Insert
	        	if (log.isDebugEnabled()) log.debug("Add new menu information...");
	        	// Add new
	        	if(menu.getIsFather()){
	        		menu.setPosition(getLstMainMenu().size()+1);
	        	}else{
	        		Menu fatherMenu = this.menuManager.getMenuById(fatherMenuId);
	        		menu.setPosition(fatherMenu.getMenuTrees().size()+1);
	        	}
	        	//Save menu to TBL_MENU
	        	menuManager.saveMenu(menu);
	        	
	        	// Update father menu to TBL_MENU_TREE
	        	if(!menu.getIsFather() && fatherMenuId!=null && !"".equals(fatherMenuId)){
	        		Menu fatherMenu = this.menuManager.getMenuById(fatherMenuId);
					MenuTree menuTree = new MenuTree();
					menuTree.setChildMenuId(menu.getId());
					menuTree.setMenu(fatherMenu);

					this.menuTreeManager.saveMenuTree(menuTree);	
	        	}
	        	
	        	//TODO: add menu to Administrator group
	        	log.debug(">>>>>>Create new menu with id: "+menu.getId());
	        	Group adminGroup = this.groupManager.getGroup(WebConstants.ROLE_ADMINISTRATOR, true);
	        	if(adminGroup!=null){
	        		Set<Menu> lstMenu = adminGroup.getMenus();
	        		//Assign new menu to Administrator group
	        		lstMenu.add(menu);
	        		adminGroup.setMenus(lstMenu);
	        		try {
	        			this.groupManager.save(adminGroup);
	        		} catch (Exception e) {
	        			// TODO: handle exception
	        			e.printStackTrace();
	        		}
	        	}
	        }
	        
	        //ActionContext.getContext().getSession().put(WebConstants.MENU_SESSION, null);
	        List<String> args = new ArrayList<String>();
	        args.add(menu.getName());
	        ActionContext.getContext().getSession().put("message", 
	                getText("menu.msg.add", args));
	                
	        return SUCCESS;
	    }

	public void setActAddMainMenu(String actAddMainMenu) {
		this.actAddMainMenu = actAddMainMenu;
	}

	public void setActEditMainMenu(String actEditMainMenu) {
		this.actEditMainMenu = actEditMainMenu;
	}

	public void setCancel(String cancel) {
		this.cancel = cancel;
	}

	public void setDelete(String delete) {
		this.delete = delete;
	}

	public void setFatherMenuId(String fatherMenuId) {
		this.fatherMenuId = fatherMenuId;
	}

	public void setGroupManager(GroupManager groupManager) {
		this.groupManager = groupManager;
	}

	public void setId(String id) {
		this.id = id;
	}

	public void setLstAllMenu(List<Menu> lstAllMenu) {
		this.lstAllMenu = lstAllMenu;
	}

	public void setLstMainMenu(List<Menu> lstMainMenu) {
		this.lstMainMenu = lstMainMenu;
	}

	public void setLstMenu(List lstMenu) {
		this.lstMenu = lstMenu;
	}
	
	
	public void setLstSubMenu(List<Menu> lstMenu) {
		this.lstSubMenu = lstMenu;
	}
	

	public void setMainMenus(List<Menu> mainMenus) {
		this.mainMenus = mainMenus;
	}

	public void setMenu(Menu menu) {
		this.menu = menu;
	}

	@Autowired
	public void setMenuManager(MenuManager menuManager) {
		this.menuManager = menuManager;
	}

	public void setMenuTreeManager(MenuTreeManager menuTreeManager) {
		this.menuTreeManager = menuTreeManager;
	}

	public void setOutputMenu(String outputMenu) {
		this.outputMenu = outputMenu;
	}

	public String up(){
    	log.debug("----> Up");
    	
    	if(this.id!=null && !"".equals(this.id)){
    		log.debug("----> Menuid: "+this.id);
    		Menu mnu = (Menu)this.menuManager.getMenuById(this.id);
    		if(mnu!=null && mnu.getPosition()!=1){
    			if(mnu.getIsFather()){
    				List<Menu> fatherMnus = this.menuManager.getFatherMenu();
    				if(fatherMnus!=null && fatherMnus.size()!=0){
    					for (Menu menu : fatherMnus) {
    						if(menu.getPosition()== mnu.getPosition()-1){
    							log.debug("Update position for menu...");
    							menu.setPosition(mnu.getPosition());
    	        				menuManager.saveMenu(menu);
    	        				
    	        				mnu.setPosition(mnu.getPosition()-1);
    	        				menuManager.saveMenu(mnu);
    	        				
    	        				break;
    						}
						}
    				}
    			}else{
    				//TODO: Gets menu that has position previous current menu
    				Menu father = this.menuTreeManager.getFatherMenu(this.id);
    				for (Iterator<MenuTree> iterator = father.getMenuTrees().iterator(); iterator.hasNext();) {
    					
    					MenuTree mnutree = iterator.next();
    					Menu previousMnu = this.menuManager.getMenuById(mnutree.getChildMenuId().toString());
						
						log.debug("Start searching menu..."+previousMnu.getName()+" | Position: "+previousMnu.getPosition());
						
						if(previousMnu.getPosition()== mnu.getPosition()-1){
							log.debug("Update position for menu...");
							previousMnu.setPosition(mnu.getPosition());
	        				menuManager.saveMenu(previousMnu);
	        				
	        				mnu.setPosition(mnu.getPosition()-1);
	        				menuManager.saveMenu(mnu);
	        				
	        				break;
						}
					}
    			}
    		}
    	}
    	
    	return SUCCESS;
    }


}
